home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / XFWD.C < prev    next >
C/C++ Source or Header  |  1997-08-18  |  30KB  |  985 lines

  1. /* Derived from fbbfwd.c */
  2.  
  3. #include "global.h"
  4. #ifdef XFWD
  5. #include "ctype.h"
  6. #include "commands.h"
  7. #include "files.h"
  8. #include "bm.h"
  9. #include "reject.h"
  10.  
  11. #if !defined(_lint)
  12. static char rcsid[] OPTIONAL = "$Id: xfwd.c,v 1.22 1997/08/19 01:19:22 root Exp root $";
  13. #endif
  14.  
  15. extern int MbForwarded, SYSOPprotect;
  16. extern int FWDpersonal, FWDbulletins;
  17. extern char FWDCall[AXALEN];
  18.  
  19. extern int indexFwdBbs (char *name);
  20. extern void importcmd (int mode, char *bbsname);
  21. extern int bid_check (register char *string);
  22. extern char *nntp_name_expansion (char *name);
  23. extern void exitfwd (struct mbx *m);
  24. static int xdosy (struct fbbpacket *msglst,struct fwd *f,int msgcnt);
  25. static int doxrecv (struct fwd *f);
  26. static int doxsend (struct fwd *f, int firstsend);
  27. static int xfwdthisarea (struct fwd *, char *, int *, int *);
  28. static void sendEndOfXBlock (struct fwd *, int, int *, int *);
  29.  
  30.  
  31. #ifdef CATALOG
  32. #include "catalog.h"
  33.  
  34. #define CAT xfwd_catalog
  35.  
  36. #define forwardingto    __STR(0)
  37. #define nodatatosend    __STR(1)
  38. #define closingfwdfile    __STR(2)
  39. #define processingarea    __STR(3)
  40. #define sendingto    __STR(4)
  41. #define sendingSXto    __STR(5)
  42. #define badSY        __STR(6)
  43. #define lostremote    __STR(7)
  44. #define receivedSYfrom    __STR(8)
  45. #define transferfailed    __STR(9)
  46. #define errorgettingtemp __STR(10)
  47. #define errorxdosycode __STR(11)
  48. #define sendingmessageto __STR(12)
  49. #define refusing    __STR(13)
  50. #define mailrefused    __STR(14)
  51. #define transfersuccess    __STR(15)
  52. #define mailsent    __STR(16)
  53. #define receivecode    __STR(17)
  54. #define sendingSY    __STR(18)
  55. #define messagesreceived __STR(19)
  56. #define receivedfrom    __STR(20)
  57.  
  58. #else /* CATALOG */
  59. static const char forwardingto[] = "%sing X-forwarding of PBBS mail to: %s ";
  60. static const char nodatatosend[] = "XFWD: No Data to send. Sending F> to %s\n";
  61. static const char closingfwdfile[] = "XFWD: Closing .fwd file for %s.\n";
  62. static const char processingarea[] = "XFWD: Processing %s message area %s for %s.\n";
  63. static const char sendingto[] = "XFWD: Sending ( to %s ) to %s";
  64. static const char sendingSXto[] = "XFWD: Sending SX Block of %d to %s\n";
  65. static const char badSY[] = "XFWD Error: Expected 'SY ' string. Received '%s' string";
  66. static const char lostremote[] = "XFWD: Lost the remote connection with %s...\n";
  67. static const char receivedSYfrom[] = "XFWD: Received '%s' from %s\n";
  68. static const char transferfailed[] = "XFWD: Transfer failed with %s......\n";
  69. static const char errorgettingtemp[] =
  70.     "XFWD: Error getting tmp file.\n"
  71.     "XFWD: We're going to pass this file to sendmsg()\n"
  72.     "XFWD: We were trying to open %s and failed.\n";
  73. static const char errorxdosycode[] = "XFWD: Error opening %s in xdosy() code.\n";
  74. static const char sendingmessageto[] = "XFWD: Sending message to %s\n";
  75. static const char refusing[] = "XFWD: Skipping message %s refused\n";
  76. static const char mailrefused[] = "XFWD: bbs mail refused: %s from %s";
  77. static const char transfersuccess[] = "XFWD: Transfer successful with %s\n";
  78. static const char mailsent[] = "PBBS mail sent: %s ";
  79. static const char receivecode[] = "XFWD: This is the receive code for %s.\n";
  80. static const char sendingSY[] = "XFWD: Sending our 'SY %d' response to %s.\n";
  81. static const char messagesreceived[] = "XFWD: Messages received (%d) from %s....\n";
  82. static const char receivedfrom[] = "XFWD: Received from %s - %s\n";
  83. #endif /* CATALOG */
  84.  
  85.  
  86. /* This code processes a SY packet from a remote system.
  87.    Return = 0 means an error was detected.
  88.             1 means an 'F>' or '>' was received from the remote system.
  89.             2 means an 'Fx' (where x is something) was received.
  90. */
  91.  
  92. static int xdosy (msglst, f, msgcnt)
  93. struct fbbpacket *msglst;
  94. struct fwd *f;
  95. int msgcnt;
  96. {
  97. int i, k;
  98. struct mbx *m;
  99. int incnt;
  100. char txtfile[80], *cp, *cp2;
  101. char tmp[AXBUF];
  102.  
  103.     m = f->m;
  104.     /* Send any data in our buffer. */
  105.     usflush (m->user);
  106.  
  107. eatprompt:
  108.     /* Get the SY line. */
  109.     if (recvline (m->user, (unsigned char *)m->line, MBXLINE) == -1 ) {
  110.         if (Xtrace)
  111.             tcmdprintf (lostremote, fwd_bbsname(m));
  112.         return 0;
  113.     }
  114.  
  115.     /* remove any line-end characters. */
  116.     rip (m->line);
  117.  
  118.     if (Xtrace)
  119.         tcmdprintf (receivedSYfrom, m->line, fwd_bbsname(m));
  120.  
  121.     /* Make sure we got a "SY " line. Anything else is an error. */
  122.     if (strnicmp (m->line, "SY ", 3) != 0) {
  123.         if (!m->fwdbbs->eatenanyprompts && !strcmp (">", m->line))    {
  124.             m->fwdbbs->eatenanyprompts = 1;
  125.             tcmdprintf ("XFWD: Eating a stray '>' (only allowed once) for %s\n", fwd_bbsname(m));
  126.             goto eatprompt;
  127.         }
  128.         tprintf (badSY, m->line);
  129.         tputs (".\n");
  130.         if (Xtrace)    {
  131.             tcmdprintf(badSY, m->line);
  132.             tcmdprintf(" from %s\n", fwd_bbsname(m));
  133.         }
  134.         return 0;
  135.     }
  136.  
  137.     m->fwdbbs->eatenanyprompts = 1;
  138.     incnt = atoi (&m->line[3]);
  139.     /* Check to see if we got too many responses. */
  140.     /* The next check makes sure we got enough of the right responses. */
  141.     if(incnt > msgcnt)
  142.         return 0;
  143.  
  144.     /* Validate SY line. Clean up unused entries. */
  145.     for (i = 0; i < XMAXMSGS; i++) {
  146.         msglst[i].accept = fbbNO;
  147.         if (i >= msgcnt) {
  148.             /* Zero out and free rest of the FS structure. */
  149.             free (msglst[i].to);
  150.             msglst[i].to = NULLCHAR;
  151.             free (msglst[i].from);
  152.             msglst[i].from = NULLCHAR;
  153.             free (msglst[i].messageid);
  154.             msglst[i].messageid = NULLCHAR;
  155.             free (msglst[i].sline);
  156.             msglst[i].sline = NULLCHAR;
  157.         }
  158.     }
  159.  
  160.     /* process the requested bid in the SY block */
  161.     for (i = 0; i < incnt; i++)    {
  162.         if (recvline (m->user, (unsigned char *)m->line, MBXLINE) == -1) {
  163.             if (Xtrace)
  164.                 tcmdprintf (transferfailed, fwd_bbsname(m));
  165.             return 0;
  166.         }
  167.         rip (m->line);
  168.         for (k = 0; k < msgcnt; k++) {
  169.             if (!stricmp (m->line, msglst[k].bid))    {
  170.                 msglst[k].accept = fbbYES;
  171.                 break;
  172.             }
  173.         }
  174.     }
  175.  
  176.     /* Now open the tempfile */
  177.     (void) tmpnam (txtfile);
  178.  
  179.     if ((m->quickfile = fopen (txtfile, "w+b")) == NULLFILE) {
  180.         tcmdprintf (errorgettingtemp, txtfile);
  181.         if (Xtrace)
  182.             log (m->user, errorxdosycode, txtfile);
  183.         return 0;
  184.     }
  185.     
  186.     /* The SY line is OK. Send the requested messages. */
  187.     for (i = 0; i < msgcnt; i++) {
  188.         kwait (NULL);
  189.         MbForwarded++;
  190.  
  191.         if(msglst[i].accept == fbbYES) {
  192.             /* Message is wanted. We need to send it.
  193.                Do not update the X-Forwarded Header yet. X-fwd does not tell us
  194.                if it received the message or not. We have to send all our
  195.                messages and then see if the connect is still there. If we get
  196.                a valid FBB Response, then we can assume that the messages were
  197.                delivered and update the X-Forwarded flag. */
  198.  
  199.             if (Xtrace)
  200.                 tcmdprintf (sendingmessageto, fwd_bbsname(m));
  201.             changearea (f->m, msglst[i].area, (int) 0);
  202.  
  203.             /* build From: line */
  204.             strncpy (m->line, msglst[i].sline, MBXLINE);
  205.             cp = strchr (m->line, '<');
  206.             if (cp == NULLCHAR)    /* shouldn't ever happen */
  207.                 continue;
  208.             cp += 2;
  209.             cp2 = strchr (cp, ' ');
  210.             if (cp2 != NULLCHAR)    /* also shouldn't ever happen */
  211.                 *cp2 = 0;
  212.             fprintf (m->quickfile, "%s%s", Hdrs[FROM], cp);
  213.  
  214.             strncpy (m->line, msglst[i].bid, MBXLINE);
  215.             cp = strpbrk (m->line, "_-");
  216.             if (cp)    {
  217.                 *cp = '@';
  218.                 fprintf (m->quickfile, "%s", cp);
  219.             }
  220.  
  221.             /* build Message-Id: line */
  222.             fprintf (m->quickfile, "\n%s<%lu@%s>\n", Hdrs[MSGID], m->mbox[msglst[i].number].bid,
  223.                 (*FWDCall) ? pax25(tmp,FWDCall) : pax25(tmp,Mycall));
  224.  
  225.             /* build To: line */
  226.             strncpy (m->line, msglst[i].sline, MBXLINE);
  227.             cp = strchr (&m->line[3], '@');
  228.             if (cp == NULLCHAR)    {
  229.                 cp = strchr (&m->line[3], ' ');
  230.                 if (cp != NULLCHAR)
  231.                     *cp = 0;
  232.                 fprintf (m->quickfile, "%s%s\n", Hdrs[TO], &m->line[3]);
  233.             } else    {
  234.                 *cp = 0;
  235.                 if (*(cp-1) == ' ')
  236.                     *(cp-1) = 0;
  237.                 if (*++cp == ' ')
  238.                     ++cp;
  239.                 cp2 = strchr (cp, ' ');
  240.                 if (cp2 != NULLCHAR)
  241.                     *cp2 = 0;
  242.                 fprintf (m->quickfile, "%s%s@%s\n", Hdrs[TO], &m->line[3], cp);
  243.             }
  244.             
  245.             /* now the msgtype line */
  246.             fprintf (m->quickfile, "%s%c\n", Hdrs[MSGTYPE], msglst[i].sline[1]);
  247.             /* and the X-BID line */
  248.             if (msglst[i].sline[1] == 'B' || ((msglst[i].sline[1] == 'P') && (!stricmp (msglst[i].area, "sysop") || !stricmp (&m->line[3], "sysop"))))
  249.                 fprintf (m->quickfile, "%s%s\n", Hdrs[XBID], msglst[i].bid);
  250.             /* and finally the subject */
  251.             fprintf (m->quickfile, "%s%s\n\n", Hdrs[SUBJECT], msglst[i].subject);
  252.  
  253.             /* Prepare the text of the message. */
  254.             sendmsg(f->m, msglst[i].number, msglst[i].bid);
  255.             fprintf (m->quickfile, "/EX\n");
  256.             f->sentThisArea++;
  257.  
  258.         } else {
  259.             /* The remote system does not want this message.
  260.                Go ahead and mark the msg as so. If the link goes
  261.                down, we still want to mark this message as unwanted.
  262.                One the link goes back up, we do not want to ask the
  263.                remote system again about this because it already
  264.                told us no. */
  265.             if (Xtrace)
  266.                 tcmdprintf (refusing, fwd_bbsname(m));
  267.             /* mark message as forwarded or deleted. */
  268.             mark_forwarded (msglst[i].fwdfile, msglst[i].fwdfileindex, '*');
  269.             m->change |= CHG_READ;
  270.             log (m->user, mailrefused, msglst[i].sline, fwd_bbsname(m));
  271.         }
  272.     }
  273.  
  274.     /* close the file. send_lzhuf() will re-open it. */
  275.     (void) fclose (m->quickfile);
  276.     m->quickfile = NULLFILE;
  277.  
  278.     /* And Send it. */
  279.     if (incnt)
  280.         (void) send_lzhuf(f, txtfile);
  281.     else
  282.         unlink (txtfile);
  283.  
  284.     /* Now we will get a line from the remote system to make sure that the
  285.        messages were received ok. */
  286.     usflush (m->user);
  287.     if (recvline (m->user, (unsigned char *)m->line, MBXLINE) == -1) {
  288.         /* There was a problem. We did not get a response from the remote
  289.            system after we sent our messages. */
  290.         if (Xtrace)
  291.             tcmdprintf (transferfailed, fwd_bbsname(m));
  292.         return 0;
  293.     } else if (toupper(*m->line) == 'F' || *m->line == '>'){    /* only mark completed, if no garbage came in */
  294.         if (Xtrace)
  295.             tcmdprintf (transfersuccess, fwd_bbsname(m));
  296.         /* We got a response back, so we can update our sent and unwanted messages. */
  297.         for (i = 0; i < msgcnt; i++) {
  298.             if (msglst[i].accept == fbbYES) {
  299.                 /* mark message as sent. */
  300.                 mark_forwarded (msglst[i].fwdfile, msglst[i].fwdfileindex, '*');
  301.                 m->change |= CHG_READ;
  302.  
  303.                 log (m->user, mailsent, msglst[i].sline);
  304. #ifdef STATS_MSG
  305.                 STATS_addmsg(1, 1);
  306. #endif
  307. #ifdef STATS_TFC
  308.                 STATS_addtfc(3, 1);
  309. #endif
  310. #ifdef STATS_FWD
  311.                 STATS_addfwd(1, 1, m->name);
  312. #endif
  313.             }
  314.  
  315.             if((!isarea (msglst[i].area) || msglst[i].type != 'B') && (stricmp(msglst[i].area, "sysop") || !SYSOPprotect))    {
  316.                 m->mbox[msglst[i].number].status |= BM_DELETE;
  317.                 statusCtl (msglst[i].area, "ctl", &m->mbox[msglst[i].number], msglst[i].number, 0);
  318.                 m->change |= CHG_DELETE;
  319.             }        
  320.  
  321.             free (msglst[i].to);
  322.             msglst[i].to = NULLCHAR;
  323.             free (msglst[i].from);
  324.             msglst[i].from = NULLCHAR;
  325.             free (msglst[i].messageid);
  326.             msglst[i].messageid = NULLCHAR;
  327.             free (msglst[i].sline);
  328.             msglst[i].sline = NULLCHAR;
  329.         }
  330.     }
  331.  
  332.     if (strnicmp (m->line,"F>", 2) == 0 || *m->line == '>')
  333.         return 1;
  334.     else
  335.         return 2;
  336. }
  337.  
  338.  
  339. /* returns 0 = okay, 1 = aborted, 2 = invalid data, 3 = lost connection, 4 = recv 'F>' */
  340. static int doxrecv(struct fwd *f)
  341. {
  342. int msgsize = 0;
  343. int i, k;
  344. char tempname[80], *cp;
  345. struct fbbpacket *msglst;
  346. struct mbx *m;
  347. int incnt = 0, mycnt = 0;
  348. int16 inchecksum, mychecksum;
  349. int retval = 0;
  350. #ifdef REJECT
  351. int rej;
  352. #endif
  353.  
  354.     msglst = f->msglst;
  355.     m = f->m;
  356.  
  357.     if (Xtrace)
  358.         tcmdprintf (receivecode, fwd_bbsname(m));
  359.  
  360.     if (!f->numtrans) {
  361.         if (recvline (m->user, (unsigned char *)m->line, MBXLINE) == -1) {
  362.             if (Xtrace)
  363.                 tcmdprintf (lostremote, fwd_bbsname(m));
  364.             return 3;
  365.         }
  366.         rip (m->line);
  367.         if (Xtrace)
  368.             tcmdprintf (receivedfrom, fwd_bbsname (m), m->line);
  369.         (void) strupr(m->line);
  370.         if (!strnicmp ("F>", m->line, 2))
  371.             return 4;
  372.         if (strnicmp ("SX ", m->line, 3))
  373.             return 2;
  374.         incnt = atoi (&m->line[3]);
  375.     } else    {
  376.         incnt = f->numtrans;
  377.         f->numtrans = 0;
  378.     }
  379.  
  380.     for (i = 0; i < XMAXMSGS; i++)
  381.         msglst[i].accept = fbbNO;
  382.  
  383.      /* Loop till we have received a all X blocks. */
  384.     for (k = 0; k < incnt; k++) {
  385.         if (recvline (m->user, (unsigned char *)m->line, MBXLINE) == -1) {
  386.             if (Xtrace)
  387.                 tcmdprintf (lostremote, fwd_bbsname(m));
  388.             return 3;
  389.         }
  390.         kwait (NULL);
  391.  
  392.         if (cutofffwding (m))
  393.             return 3;
  394.  
  395.         /* strip any trailing NL characters. */
  396.         rip(m->line);
  397.  
  398.         if (Xtrace)
  399.             tcmdprintf (receivedfrom, fwd_bbsname(m), m->line);
  400.         log (m->user, "XFWD %s: %s", fwd_bbsname(m), m->line);
  401.  
  402. #ifdef REJECT
  403.         rej = reject (m->line, 1, 1);
  404.         if (rej != REJ_REJECT && rej != REJ_DEFER)
  405. #endif
  406.             if (!bid_check (m->line))
  407.                 strncpy (msglst[mycnt++].bid, m->line, 15);
  408.  
  409.     }
  410.  
  411.  
  412.     if (Xtrace)
  413.         tcmdprintf (sendingSY, mycnt, fwd_bbsname(m));
  414.     tprintf ("SY %d\n", mycnt);
  415.     for (k = 0; k < mycnt; k++)
  416.         tprintf ("%s\n", msglst[k].bid);
  417.     usflush(m->user);
  418.  
  419.     if (mycnt)    {
  420.         /* receive the SS block, with the compressed data size */
  421.         if (recvline (m->user, (unsigned char *)m->line, MBXLINE) == -1) {
  422.             if (Xtrace)
  423.                 tcmdprintf (lostremote, fwd_bbsname(m));
  424.             return 3;
  425.         }
  426.         if (Xtrace)
  427.             tcmdprintf (receivedfrom, fwd_bbsname(m), m->line);
  428.         msgsize = atoi (&m->line[3]);
  429.         cp = skipnonwhite (&m->line[3]);
  430.         cp = skipwhite (cp);
  431.         inchecksum = (int16) atol (cp);
  432.  
  433.         /* The remote system will start sending the message data. */
  434.         /* Set up a temp name to receive the file. */
  435.         sprintf (tempname, "%s/%s.imp", IMPORTDir, m->name);
  436.  
  437.         /* Receive the messages and uncompress them. */
  438.         strncpy (f->iFile, tmpnam(NULL), FWDFILELEN);
  439.         strncpy (f->oFile, tempname, FWDFILELEN);
  440.         if (recv_lzhuf(f, msgsize, &mychecksum) == 0)
  441.                        return 1;
  442.                 if (inchecksum != mychecksum)    {
  443.                        if (Xtrace)
  444.                 tcmdprintf ("XFWD: Checksum error with %s: received %u, calculated %u\n", fwd_bbsname(m), inchecksum, mychecksum);
  445.             retval = 1;
  446.             unlink (f->oFile);
  447.         } else
  448.             importcmd (0, m->name);
  449.         /* remove the other file */
  450.         unlink (f->iFile);
  451.  
  452.         if (Xtrace && !retval)
  453.             tcmdprintf (messagesreceived, mycnt, fwd_bbsname(m));
  454.     }
  455.     return retval;
  456. }
  457.  
  458.  
  459. /****************************************************************************************/
  460. /* This code is called when we've 25 X-Blocks, or we don't have any more                */
  461. /* messages to send.                                                                    */
  462. /****************************************************************************************/
  463. static void sendEndOfXBlock (f, msgcnt, Xok, Xdone)
  464. struct fwd *f;
  465. int msgcnt, *Xok, *Xdone;
  466. {
  467. int rc;
  468. struct mbx *m;
  469. struct fbbpacket *msglst;
  470.  
  471.     /* point pointers to their proper location. */
  472.     msglst = f->msglst;
  473.     m = f->m;
  474.  
  475.     if (Xtrace)
  476.         tcmdprintf (sendingSXto, msgcnt, fwd_bbsname(m));
  477.     tprintf ("SX %d\n", msgcnt);
  478.     for (rc = 0; rc < msgcnt; rc++)
  479.         tprintf ("%s\n", msglst[rc].bid);
  480.  
  481.     /* Process an incoming SY and receive messages. */
  482.     rc = xdosy(msglst, f, msgcnt);
  483.     if (!rc) {
  484.         *Xok   = FALSE;
  485.         *Xdone = TRUE;
  486.     } else if (rc == 1) {
  487.         *Xok   = TRUE;
  488.         *Xdone = FALSE;
  489.     } else if (rc == 2) {
  490.         *Xok   = TRUE;
  491.         *Xdone = TRUE;
  492.     }
  493. }
  494.  
  495.  
  496. /****************************************************************************************/
  497. /* This code is called for each message area we forward to.                             */
  498. /****************************************************************************************/
  499. static int xfwdthisarea (f, area, Xok, Xdone)
  500. struct fwd *f;
  501. char *area;
  502. int *Xok, *Xdone;
  503. {
  504. char line[MBXLINE];
  505. int err = 0;
  506. int msgcnt = 0;
  507. int Tmsgcnt = 0;
  508. int theindex = 0;
  509. int changed = 0;
  510. int rc, i;
  511. long bid;
  512. long curpos;
  513. long tempsize;
  514. char *pszBid;
  515. long msgsize = 0;
  516. #if 0
  517. int passes = 0;
  518. #endif
  519.  
  520. struct let *cmsg;
  521. struct mbx *m;
  522. struct fbbpacket *msglst;
  523.  
  524. /* for makecl() */
  525. int bulletin;
  526. char *newto   = NULLCHAR;
  527. char line2[64];
  528. char thebid[LINELEN];
  529. char subject[LINELEN];
  530. struct arealist    *a;
  531.  
  532.  
  533.     /* point pointers to their proper location. */
  534.     msglst = f->msglst;
  535.     m = f->m;
  536.  
  537.     /* public area? */
  538.     bulletin = isarea (area);
  539.  
  540.     if (Xtrace && FWDareatrace)
  541.         tcmdprintf (processingarea, bulletin ? "Public  " : "Private ", area, fwd_bbsname(m));
  542.  
  543.     /* Initialize variables. */
  544.     *Xok = TRUE;
  545.     *Xdone = FALSE;
  546.  
  547.     if (bulletin && (!FWDbulletins || !m->fwdbbs->bulletins))    {
  548.         if (Xtrace)
  549.             tcmdprintf ("Skipping any bulletins in area '%s' for %s\n", area, m->fwdbbs->name);
  550.         return Tmsgcnt;
  551.     }
  552.     if (!bulletin && (!FWDpersonal || !m->fwdbbs->personals))    {
  553.            if (Xtrace)
  554.             tcmdprintf ("Skipping any personal messages in area '%s' for %s\n", area, m->fwdbbs->name);
  555.         return Tmsgcnt;
  556.     }
  557.  
  558.     /* check if there are any messages in this area that need to be forwarded. */
  559.     rewind (f->fwdfile);                   /* rewind forward file...       */
  560.     curpos = 0L;                           /* set file position            */
  561.     /* read each line in the .fwd file. exit loop on error or no more lines */
  562.     while (!err && fgets (line, MBXLINE, f->fwdfile) != NULLCHAR) {
  563.         (void) fflush (f->fwdfile);
  564.         kwait (NULL);                        /* Give control back to system. */
  565.         if (*line != '*' && *line != '!' && *line != '-') {    /* '*' means this has been done          */
  566.                                     /* '!' means this is blocked             */
  567.                                              /* '-' means this was sent to an ALT BBS */
  568.             if ((pszBid = strpbrk(&line[1], " \t")) != NULLCHAR)    /* get the bid. */
  569.                 *pszBid++ = '\0';
  570.             else
  571.                 continue;                /* improperly formatted */
  572.             if (!stricmp (area, &line[1]))  {        /* is this the correct area?    */
  573.                 bid = atol (pszBid);            /* get the message number       */
  574.                 if (!changed)   {            /* are we in the right area...  */
  575.                     m->area[0] = 0;            /* force a reload of index      */
  576.                     changearea(m, area, (int) 0);    /*    if not... go there now... */
  577.                     changed = 1;            /*       and update the flag....*/
  578.                 }
  579.                 /* Set the 'found message flag' to false. */
  580.                 theindex = 0;
  581.                 /* for each message in the .txt file... */
  582.                 for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
  583.                     /* find the message we're supposed to forward. */
  584.                     if ((bid == cmsg->bid) && !(cmsg->status & BM_DELETE))  {
  585.                         /* this is the message... set the flag and break. */
  586.                         theindex = i;
  587.                         break;
  588.                     }
  589.  
  590.                 if (theindex && m->fwdbbs && m->fwdbbs->maxsize && cmsg->size > m->fwdbbs->maxsize)    {
  591.                     if (Xtrace)
  592.                         tcmdprintf ("XFWD: Deferring large message to %s, allowed=%ld, size=%ld\n", m->fwdbbs->name, m->fwdbbs->maxsize, cmsg->size);
  593.                 } else    {
  594.                     /* if we didn't find the message... it must have been deleted. We can   */
  595.                     /* mark the message as forwarded so we don't try it again. This is just */
  596.                     /* done for performance reasons.                                        */
  597.                     /* Also, if found, block it. Then if an I/O error occurs, this message  */
  598.                     /* will be skipped until all others have a chance to get passed         */
  599.                     mark_forwarded (f->fwdfile, curpos, (!theindex) ? '*' : '!');
  600.  
  601.                     /* if the 'found message flag' is set.... */
  602.                     if (theindex && !(cmsg->status & (BM_ONHOLD | BM_DELETE))) {
  603.                         newto = NULLCHAR;    /* just in case */
  604.                         if (m->fwdbbs)    /* just in case */
  605.                             for (a = m->fwdbbs->areas; a; a = a->next)
  606.                                 if (!stricmp (area, a->name))
  607.                                     newto = a->forceaddr;
  608.  
  609.                         /* Prepare the FB line. */
  610.                         bulletin = isarea (area);    /* reset, just in case */
  611.                         rc = makecl(m, theindex, newto, line2, subject, thebid, &bulletin);
  612.                         if (rc == -2)    {    /* delete the message */
  613.                             mark_forwarded (f->fwdfile, curpos, '*');
  614.                             if ((!isarea (area) || m->stype != 'B') && (stricmp (area, "sysop") || !SYSOPprotect)) {
  615.                                 m->mbox[i].status |= BM_DELETE;
  616.                                 statusCtl (area, "ctl", &m->mbox[i], i, 0);
  617.                                 m->change |= CHG_DELETE;
  618.                             }
  619.                         } else if (rc != -1) {    /* If command line ok, store it. */
  620.                             /* Copy SEND line for message log. */
  621.                             free (msglst[msgcnt].sline);
  622.                             (void) strupr (msglst[msgcnt].sline = strdup (line2));
  623.                             msglst[msgcnt].fwdfileindex = curpos;
  624.                             msglst[msgcnt].fwdfile = f->fwdfile;
  625.  
  626.                             /* store the message type */
  627.                             msglst[msgcnt].type = msglst[msgcnt].sline[1];
  628.  
  629.                             /* Keep track of the subject.    */
  630.                             free (msglst[msgcnt].subject);
  631.                             msglst[msgcnt].subject = strdup (subject);
  632.  
  633.                             /* Keep track of the message area */
  634.                             free (msglst[msgcnt].area);
  635.                             msglst[msgcnt].area = strdup (area);
  636.  
  637.                             /* Keep track of message number in area. */
  638.                             msglst[msgcnt].number = i;
  639.  
  640.                             /* Keep track of makecl() modified bid. */
  641.                             strncpy (msglst[msgcnt].bid, &thebid[1], 15);
  642.  
  643.                             if (Xtrace)
  644.                                 tcmdprintf (sendingto, fwd_bbsname(m), line2);
  645.  
  646.                             msgcnt++;
  647.                             msgsize += m->mbox[theindex].size;
  648.                             /* If we have filled our SX Block */
  649.                             if (msgcnt >= XMAXMSGS || (m->fwdbbs && m->fwdbbs->fbbsize && msgsize > m->fwdbbs->fbbsize)) {
  650.                                 sendEndOfXBlock (f, msgcnt, Xok, Xdone);
  651.                                 Tmsgcnt += msgcnt;
  652.                                 msgcnt = 0;
  653.                                 msgsize = 0;
  654.                             }
  655.                         }
  656.                     }
  657.                 }
  658.             }
  659.         } /* end if() */
  660.         /* If we got an error from dofs() or the response
  661.            from dofs() was 2, we are done with this message
  662.            transfer. If we got a 1 from dofs() we can send
  663.            more messages now so we do not need to exit. */
  664.         if (*Xdone)
  665.             break;
  666.         curpos = ftell (f->fwdfile);         /* get file position            */
  667.         tempsize = m->mysize;
  668.         if(isnewprivmail (m, "fwd") > 0)    {
  669.             m->mysize = tempsize;
  670.             break;
  671.         }
  672.     } /* end while() */
  673.  
  674.     /* If we have any left over messages... send them now. */
  675.     if (msgcnt) {
  676.         sendEndOfXBlock (f, msgcnt, Xok, Xdone);
  677.         Tmsgcnt += msgcnt;
  678.     }
  679.  
  680.     return Tmsgcnt;
  681. }
  682.  
  683.  
  684. /* This code is used to figure out what messages need to be sent. */
  685. static int doxsend (f, firstsend)
  686. struct fwd *f;
  687. int firstsend;
  688. {
  689. int    err = 0;
  690. int    Tmsgcnt;
  691. int    Xdone;
  692. int    Xok = 0;
  693. long   pos;
  694. char   name[256];
  695. struct arealist *fwdarea;
  696. struct mbx *m;
  697. int    areasused;
  698. int    equals, bang;
  699.  
  700.     /* point pointers to their proper location. */
  701.     m = f->m;
  702.  
  703.     /* figure out name of the user. */
  704.     sprintf (name, "%s/%s", Mailspool, m->name);
  705.     (void) nntp_name_expansion (name);
  706.  
  707.     /* Save data */
  708.     strncpy (f->savefsline, m->line, MBXLINE);
  709.  
  710.     /* figure out .fwd file name and see if it exist. It it doesn't exist...   */
  711.     /* .... we have nothing for this user.                                     */
  712.     strcat (name, ".fwd");
  713.     (void) strlwr (name);
  714.     if ((f->fwdfile = fopen (name, UPDATE_TEXT)) == NULLFILE)
  715.         /* the file doesn't exist. This should only occur with a reverse forward request. */
  716.         return 2;
  717.  
  718.     /* Check to see if we have any info to send and make sure it is the
  719.        right time to send data. */
  720.     if (!f->m->fwdbbs && fwdinit (f->m, 1) == -1)
  721.         /* The bbs is not in the forward.bbs file or it is the wrong time to send.
  722.            Return a 0 to indicate that we have no data for the remote system. */
  723.         return 0;
  724.  
  725.     /* Now grab a subchannel slot, if needed. It is available, or fwdinit()
  726.        would have returned -1. */
  727.     (void) checksubchannel (m, 1);
  728.  
  729.     /* restore data. */
  730.     strncpy(m->line, f->savefsline, MBXLINE);
  731.  
  732. checkloop:
  733.     kwait (NULL);
  734.  
  735.     /* Initialize the fwdarea pointer. This is the list of areas we forward to. */
  736.     fwdarea = m->fwdbbs->areas;
  737.  
  738.     /* for each area in the fwdarea list do.... */
  739.     err = 0;
  740.     Tmsgcnt = 0;
  741.     areasused = 0;
  742.     (void) isnewprivmail (m, "fwd");        /* first time, just sets m->mysize */
  743.     while (!err && fwdarea) {
  744.  
  745.         kwait (NULL);
  746.         if (cutofffwding (m))    {
  747.             Xok = 0;
  748.             break;
  749.         }
  750.  
  751.         f->sentThisArea = 0;
  752.         Tmsgcnt += xfwdthisarea (f, fwdarea->name, &Xok, &Xdone);
  753.         if (Xdone || Tmsgcnt)
  754.             break;
  755.         if (isnewprivmail (m, "fwd") > 0)
  756.             goto checkloop;
  757.         if (f->sentThisArea)    /* if we got something in this area */
  758.             areasused += 1;
  759.         fwdarea = fwdarea->next; /* Do next area. */
  760.     } /* end while() */
  761.  
  762.     if (!Xok)    {    /* We had an error. */
  763.         (void) fclose (f->fwdfile);
  764.         return 3;
  765.     }
  766.  
  767.     /* this next piece (and the sections above that affect areasused), make
  768.        this go BACK to check for messages added into earlier areas. This
  769.        prevents us from disconnecting if some new info JUST came in. */
  770.     if (areasused)
  771.         goto checkloop;
  772.  
  773.     if (Xtrace)
  774.         tcmdprintf (closingfwdfile, fwd_bbsname(m));
  775.  
  776.     /* See if we can remove the .fwd file. */
  777.     fwdlockit (m->name);
  778.     rewind (f->fwdfile);
  779.     equals = 0;
  780.     bang = 0;
  781.     while (pos = ftell (f->fwdfile), fgets (f->line, MBXLINE, f->fwdfile) != NULLCHAR) {
  782.         kwait (NULL);
  783.         if (*f->line == '=')    {
  784.             mark_forwarded(f->fwdfile, pos, '!');
  785.             equals++;
  786.             err = 1;
  787.         } else if (*f->line == '!')    {
  788.             mark_forwarded(f->fwdfile, pos, ' ');
  789.             bang++;
  790.             err = 1;
  791.         } else if(*f->line != '*' && *f->line != '-')    {       /* if not already done */
  792.             err = 1;
  793. #if 0
  794.             break;
  795. #endif
  796.         }
  797.     }
  798.  
  799.     if (firstsend && !Tmsgcnt && bang && !equals)    {
  800.         /* we didn't transfer any messages, there seems to have been all
  801.            messages marked with '!', so we will re-scan */
  802.         if (Xtrace)
  803.             tcmdprintf ("XFWD: Relooping on .fwd file for %s - 1st scan since last aborted session\n", fwd_bbsname(m));
  804.         fwdunlockit (m->name);
  805.         goto checkloop;
  806.     }
  807.    
  808.     /* one last check, to avoid deleting a file that JUST added a record */
  809.     if (isnewprivmail (m, "fwd") > 0)    {
  810.         if(Xtrace)
  811.             tcmdprintf ("XFWD: Relooping on .fwd file for %s - new messages received\n", fwd_bbsname(m));
  812.         fwdunlockit (m->name);
  813.         goto checkloop;
  814.     }
  815.  
  816.     (void) fclose (f->fwdfile);
  817.     if (!err)
  818.         (void) remove (name);
  819.  
  820.     fwdunlockit (m->name);
  821.     kwait (NULL);
  822.     if (!Tmsgcnt)
  823.         /* We had no data. */
  824.         return 2;
  825.     return 1;
  826. }
  827.  
  828.  
  829. /* This is the main entry point for X-forwarding. */
  830. int
  831. doxfwd(argc,argv,p)
  832. int argc;
  833. char *argv[];
  834. void *p;
  835. {
  836. struct fwd f;
  837. struct mbx *m;
  838. struct fbbpacket *msglst;
  839. int i;
  840. int firstsend = 1;
  841. int Done;
  842. int rc;
  843. int FBBRdone = FALSE;         /* Receiving system has no more data. */
  844. int NeedData;
  845. int X_fwd;
  846.  
  847.     
  848.     f.m = (struct mbx *)p;
  849.     m   = f.m;
  850.  
  851.     log (f.m->user, forwardingto, (argc) ? "Incom" : "Outgo", m->name);
  852.  
  853.     /* First verify that this is a system that supports X-forwarding. */
  854.     if(!(f.m->sid & MBX_XFWD)) {
  855.         tputs ("Huh?\n");
  856.         usflush (m->user);
  857.         return -1;
  858.     }
  859.  
  860.     /* Get memory for the msglst array. */
  861.     f.msglst = (struct fbbpacket *)callocw ((unsigned)XMAXMSGS, sizeof(struct fbbpacket));
  862.     m->msglst = msglst = f.msglst;
  863.  
  864.     NeedData = FALSE;
  865.     Done     = FALSE;
  866.     X_fwd   = FALSE;
  867.  
  868.     /* See if we were called because we received a SX from the remote system. */
  869.     if (!argc) {
  870.         f.m->state = MBX_FORWARD; /* We are in send mode. */
  871.         FBBRdone   = FALSE;
  872.         NeedData   = TRUE;
  873.         X_fwd     = TRUE;
  874.     } else if(argv[0][0] == 'S' && m->stype == 'X') {
  875.         if (argc != 2) {
  876.             tputs ("Huh?\n");
  877.             usflush (m->user);
  878.             Done = TRUE;
  879.         } else {
  880.             f.numtrans = (char) atoi (argv[1]);
  881.             /* indicate that we are in receive mode. */
  882.             f.m->state = MBX_REVFWD;
  883.             FBBRdone = FALSE;
  884.         }
  885.     } else {
  886.         /* Must have received a F> from the remote system. */
  887.         f.m->state = MBX_FORWARD; /* We are in send mode. */
  888.         FBBRdone = TRUE;
  889.     }
  890.  
  891.  
  892.     if(Xtrace)
  893.         tcmdprintf ("XFWD: %sing forwarding started with %s.\n", (argc) ? "Incom" : "Outgo", fwd_bbsname(m));
  894.  
  895.     while (!Done) {
  896.         kwait (NULL);
  897.         if (f.m->state == MBX_REVFWD) {
  898.             if (Xtrace)
  899.                 tcmdprintf ("XFWD: Receiving data from %s.\n", fwd_bbsname(m));
  900.  
  901.             if (NeedData)    {    /* null out the line. */
  902.                 f.m->line[0] = 0;
  903.                 f.numtrans = 0;
  904.             }
  905.  
  906.             NeedData = TRUE;
  907.             /* Receive data from remote system. Process SX block. */
  908.             rc = doxrecv (&f);
  909.             if (rc == 4)    {    /* Remote system sent us a F> */
  910.                 if (X_fwd)
  911.                     Done = TRUE;
  912.                 else    /* Change status. */
  913.                     f.m->state = MBX_FORWARD;
  914.                 FBBRdone = TRUE;
  915.             } else if (rc)
  916.                 Done = TRUE;
  917.             if (Done != TRUE)    {
  918.                 tputs ((X_fwd == TRUE) ? "F>\n" : ">\n");
  919.                 if (Xtrace)
  920.                     tcmdprintf ("XFWD: Sending '%s>' to %s\n",
  921.                         (X_fwd == TRUE) ? "F" : "", fwd_bbsname(m));
  922.                 usflush (m->user);
  923.             }
  924.         } else {
  925.             if (Xtrace)
  926.                 tcmdprintf ("XFWD: Sending data to %s.\n", fwd_bbsname(m));
  927.  
  928.             NeedData = FALSE;
  929.             /* Change status. */
  930.             rc = doxsend (&f, firstsend);
  931.             firstsend = 0;
  932.             if (rc == 3)        /* An error occured. */
  933.                 break;
  934.             if ((rc == 0) || (rc == 2)) {
  935.                 /* We had no data for remote system. */
  936.                 if (FBBRdone) {
  937.                 /* They have no more data for us....
  938.                    So we break out of this loop and disconnect.
  939.                  */
  940.                     break;
  941.                 } else {
  942.                     /* Tell them that we do not have any data for them. */
  943.                     if(Xtrace)
  944.                         tcmdprintf (nodatatosend, fwd_bbsname(m));
  945.                     tputs ("F>\n");
  946.                     /* Change status. */
  947.                     f.m->state = MBX_REVFWD;
  948.                     usflush (m->user);
  949.                     NeedData = TRUE;
  950.                 }
  951.             }
  952.         }
  953.     } /* endwhile */
  954.  
  955.     /* free anything in the msglst array. */
  956.     for (i = 0; i < XMAXMSGS ; i++) {
  957.         free (msglst[i].to);
  958.         free (msglst[i].from);
  959.         free (msglst[i].messageid);
  960.         free (msglst[i].sline);
  961.         msglst[i].to = msglst[i].from = msglst[i].messageid = msglst[i].sline = NULLCHAR;
  962.     }
  963.  
  964.     /* Now free the msglst array. */
  965.     free (msglst);
  966.  
  967.     usflush (m->user);
  968.     releasesubchannel (m);    /* just in case */
  969.     if (X_fwd)    {
  970.         exitfwd(m);
  971.         return 0;
  972.     } else    {
  973.         /* This section marks the last fwd session time */
  974.         if ((i = indexFwdBbs (fwd_bbsname(m))) != NUMFWDBBS)    {
  975.             MyFwds[i].laston = time (NULL);
  976.             MyFwds[i].lastactivity = time (NULL);
  977.         }
  978.         m->state = MBX_CMD;
  979.         return domboxbye(0,NULL,m);
  980.     }
  981. }
  982.  
  983. #endif /* ifdef XFWD */
  984.  
  985.